4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
15 // ===========================================================================
17 // Purpose: Compiles .rc files to .satellite files
18 // ===========================================================================
21 #include "palstartup.h"
23 #define BUF_SIZE (4097*2) //Number comes from resource compiler mini spec
24 #define PATH_BUF_SIZE _MAX_PATH
25 #define UNKNOWN_LINE_NUMBER -1
28 /* By default, cc treats .rc files as something to be linked in and
29 * therefore won't run the preprocessor on them. The '-x c' option
30 * tells cc to treat the following file as a C file.
31 * On Darwin, we don't want to use the cpp-precomp preprocessor.
34 #define COMPILER_PREPROCESSOR_FLAGS "-E -no-cpp-precomp -DRC_INVOKED=1 -DFEATURE_PAL=1 -x c"
36 #define COMPILER_PREPROCESSOR_FLAGS "-E -DRC_INVOKED=1 -DFEATURE_PAL=1 -x c"
37 #endif // __APPLE_CC__
39 #define COMPILER_NAME "gcc"
41 #define COMPILER_NAME "gcc.exe"
43 #define LINEMARKER_PREFIX '#'
44 #define DEFINE_PREFIX "-D"
45 #define INCLUDE_PREFIX "-I"
46 #define TARGET_PREFIX "-o"
48 #define COMPILER_PREPROCESSOR_FLAGS "/nologo /EP /DRC_INVOKED=1 /DFEATURE_PAL=1"
49 #define COMPILER_NAME "cl.exe"
50 #define LINEMARKER_PREFIX "#line"
51 #define DEFINE_PREFIX "/D"
52 #define INCLUDE_PREFIX "/I"
56 #define PATH_SEPARATOR_CHAR '/'
57 #define PATH_SEPARATOR_STRING "/"
59 #define PATH_SEPARATOR_CHAR '\\'
60 #define PATH_SEPARATOR_STRING "\\"
63 int getEscapeCharacter (char * input
, char * output
);
64 LPSTR
FormatString(LPSTR inputString
);
65 LPSTR
convertToUTF8(LPSTR inputString
);
66 int __cdecl
steCompare(const void *first
, const void *second
);
67 void ProcessParameters(int argc
, LPSTR argv
[], LPSTR
* compilerOptions
);
68 void printUsage(LPSTR message
);
69 void crashAndBurn(LPSTR message
, int lineNumber
, LPSTR file
, LPSTR badline
);
70 void updateLineNumber(LPSTR line
, int * lineNumber
, LPSTR
* lineFile
);
71 void preProcessFile(LPSTR compilerOptions
);
72 void clearBlanksAndLineUpdates(FILE * file
, int * lineNumber
,
74 LPSTR
* textline
, BOOL checkCurrent
);
75 BOOL
startsWithLineMarker(const char *line
);
76 BOOL __stdcall
ConsoleControlHandler(DWORD dwCtrlType
);
77 LPSTR
changeExtension(LPSTR filename
, LPSTR oldExt
, LPSTR newExt
);
78 void removeDefinition(FILE * file
,
80 BOOL linesBeforeBegin
,
83 int LexOneLine(char *p
);
84 ULONG
Expr_Eval(void);
93 LPSTR outFilename
= NULL
;
94 LPSTR strippedFilename
;
101 int __cdecl
main(int argc
, LPSTR argv
[])
105 LPSTR lineFile
= NULL
;
116 LPSTR stringValueFormatted
;
117 LPSTR stringValueOut
;
118 STRING_TABLE_ENTRY
* stringtable
= NULL
;
119 int stringTableCounter
= 0;
121 char * pchStartQuote
;
123 LPSTR compilerOptions
;
130 BOOL OutFileWritten
= FALSE
;
133 alloctextline
= (LPSTR
)malloc(BUF_SIZE
);
134 if(alloctextline
== NULL
){
135 crashAndBurn("Out of memory - alloctextline",
136 UNKNOWN_LINE_NUMBER
, "", "");
139 SetConsoleCtrlHandler(ConsoleControlHandler
, TRUE
);
147 compilerOptions
= (LPSTR
)malloc(sizeof(" " COMPILER_PREPROCESSOR_FLAGS
" "));
149 if (compilerOptions
== NULL
)
150 crashAndBurn("Out of memory - compilerOptions",
151 UNKNOWN_LINE_NUMBER
, "", "");
153 strcpy(compilerOptions
, " " COMPILER_PREPROCESSOR_FLAGS
" ");
155 ProcessParameters(argc
, argv
, &compilerOptions
);
157 if (inFilename
== NULL
){
158 printUsage("A filename must be specified\n");
161 printf("\n\n%s\n", inFilename
);
165 printf("Preprocessing resource file...\n");
168 filenameStart
= strrchr(inFilename
, PATH_SEPARATOR_CHAR
);
169 if (filenameStart
== NULL
) {
170 filenameStart
= inFilename
;
175 lineFile
= (LPSTR
)malloc(strlen(filenameStart
) + 1);
176 if (lineFile
== NULL
) {
177 crashAndBurn("Out of memory - string allocation",
178 UNKNOWN_LINE_NUMBER
, "", "");
180 strcpy(lineFile
, filenameStart
);
183 // The pre processed file is created in the temp directory
184 char szTempName
[MAX_PATH
];
185 char szTempPath
[MAX_PATH
];
187 if (!GetTempPathA(MAX_PATH
, szTempPath
)) {
188 crashAndBurn("GetTempPath failed!", UNKNOWN_LINE_NUMBER
,"","");
191 if (!GetTempFileNameA(szTempPath
, "RC", 0, szTempName
)) {
192 crashAndBurn("GetTempFileNameA failed!", UNKNOWN_LINE_NUMBER
,"","");
195 strippedFilename
= (LPSTR
)malloc(strlen(szTempName
) + 1);
196 if (strippedFilename
== NULL
) {
197 crashAndBurn("Out of memory - strippedFileName",
198 UNKNOWN_LINE_NUMBER
, "", "");
201 strcpy(strippedFilename
, szTempName
);
204 preProcessFile(compilerOptions
);
206 free(compilerOptions
);
210 printf("Reading Preprocessed File %s\n", strippedFilename
);
212 //Open stripped input file
213 strippedrc
= fopen(strippedFilename
, "r");
214 if (strippedrc
== NULL
){
215 crashAndBurn("Preprocessor failure", UNKNOWN_LINE_NUMBER
, "", "");
218 textline
=alloctextline
;
219 while (fgets(textline
, BUF_SIZE
, strippedrc
) != NULL
){
223 clearBlanksAndLineUpdates(strippedrc
, &lineNumber
, &lineFile
,
225 if (textline
== NULL
){
229 textline
[(strlen(textline
)-1)] = '\0'; //Remove trailing newline
231 textlinetotok
= (LPSTR
)malloc(strlen(textline
) + 1);
233 if(textlinetotok
== NULL
){
234 crashAndBurn("Out of memory - textlinetotok",
235 UNKNOWN_LINE_NUMBER
, "", "");
238 strcpy(textlinetotok
, textline
);
240 firstword
= strtok(textlinetotok
, " \t\n");
241 assert(firstword
!= NULL
); //BLANK LINES WERE REMOVED
243 if (!strcmp(firstword
, "STRINGTABLE")){
246 printf("StringTable resource found on line %i in \n\t%s, processing\n",
247 lineNumber
, lineFile
);
249 clearBlanksAndLineUpdates(strippedrc
,&lineNumber
,
250 &lineFile
, &textline
, FALSE
);
251 if (textline
== NULL
){
252 crashAndBurn("Unexpected end of file in Stringtable",
253 lineNumber
, lineFile
, "");
258 //MAKE SURE BEGIN EXISTS
259 textlinetotok
= (LPSTR
)malloc(strlen(textline
) + 1);
260 if (textlinetotok
== NULL
)
261 crashAndBurn("Out of memory -textlinetotok",
262 UNKNOWN_LINE_NUMBER
,"","");
263 textlinetotok
= strcpy(textlinetotok
, textline
);
265 firstword
= strtok(textlinetotok
, " \t\n");
266 assert(firstword
!= NULL
); //BLANK LINES WERE REMOVED
268 if ( (strcmp(firstword
,"BEGIN")) ){ //NO BEGIN, CHECK FOR {
269 textline
= strchr(textline
, '{');
270 if (textline
== NULL
){
271 crashAndBurn("No BEGIN or { following STRINGTABLE",
272 lineNumber
, lineFile
, textline
);
277 textline
= alloctextline
;
278 if(fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
279 crashAndBurn("end of file before END in stringtable",
280 lineNumber
, lineFile
, "");
290 clearBlanksAndLineUpdates(strippedrc
,
291 &lineNumber
, &lineFile
, &textline
, TRUE
);
292 if (textline
== NULL
){
293 crashAndBurn("end of file before END in stringtable",
294 lineNumber
, lineFile
, "");
297 textlinetotok
= (LPSTR
)malloc(strlen(textline
) + 1);
298 if (textlinetotok
== NULL
)
299 crashAndBurn("Out of memory -textlinetotok",
300 UNKNOWN_LINE_NUMBER
,"","");
301 textlinetotok
= strcpy(textlinetotok
, textline
);
303 firstword
= strtok(textlinetotok
, " \t\n");
304 assert(firstword
!= NULL
); //BLANK LINES WERE REMOVED
306 if (!strcmp(firstword
,"END")|| !strcmp(firstword
, "}")){
311 if (stringtable
== NULL
){ //First time through loop, no memory yet.
312 stringtable
= (STRING_TABLE_ENTRY
*)malloc(sizeof(STRING_TABLE_ENTRY
));
313 if (stringtable
== NULL
){
314 crashAndBurn("Out of memory - stringtable",
315 UNKNOWN_LINE_NUMBER
, "", "");
318 else { //Make room for additional entry
319 stringtable
= (STRING_TABLE_ENTRY
*)realloc(stringtable
,
320 (stringTableCounter
+ 1) *
321 sizeof(STRING_TABLE_ENTRY
));
322 if (stringtable
== NULL
){
323 crashAndBurn("Out of memory - stringtable",
324 UNKNOWN_LINE_NUMBER
, "", "");
328 //GET FRESH COPY OF TEXTLINE TO TOKENIZE WITH DIFFERENT SPACERS
331 textlinetotok
= (LPSTR
)malloc(strlen(textline
) + 1);
332 if (textlinetotok
== NULL
)
333 crashAndBurn("Out of memory -textlinetotok",
334 UNKNOWN_LINE_NUMBER
,"","");
335 textlinetotok
= strcpy(textlinetotok
, textline
) ;
337 stringID
= strtok(textlinetotok
, "\"");
338 if (stringID
== NULL
)
339 crashAndBurn("Bad Format in StringTable",
340 lineNumber
, lineFile
, textline
);
342 if (strstr(stringID
, "L") != NULL
)
343 *(strstr(stringID
, "L")) = '\0';
345 if(!LexOneLine(stringID
))
346 crashAndBurn("StringID in bad form",
347 lineNumber
, lineFile
, textline
);
349 // Note: we are indexing only using the low 16 bits
350 exprResult
= Expr_Eval();
351 if (exprResult
== -1) {
352 // Expr_Eval returns -1 if there is no valid number
353 crashAndBurn("No StringID found",
354 lineNumber
, lineFile
, textline
);
356 stringIDint
= (UINT16
) exprResult
;
359 // Cannot use strtok because it will ignore quotes in resources
360 // that appear as "this has a ""quoted"" string"
361 pchStartQuote
= strchr(textline
, '\"');
362 pchEndQuote
= strrchr(textline
, '\"');
364 if (pchEndQuote
!= NULL
&& pchEndQuote
!= pchStartQuote
)
366 stringLen
= pchEndQuote
- pchStartQuote
+ 1;
367 stringValue
= (LPSTR
)malloc(stringLen
+ 1);
368 if (stringValue
== NULL
)
369 crashAndBurn("Out of memory - stringValue",
370 lineNumber
, lineFile
, textline
);
371 stringValue
= strncpy(stringValue
, pchStartQuote
, stringLen
);
372 stringValue
[stringLen
-1] = '\0';
375 if (stringValue
== NULL
){
376 //STRING VALUE WAS NOT ON SAME LINE AS STRING ID
377 //SEARCH UPCOMING LINES TO SEE IF WE CAN FIND IT
379 int oldLineNumber
= lineNumber
;
381 clearBlanksAndLineUpdates(strippedrc
,
382 &lineNumber
, &lineFile
, &textline
, FALSE
);
383 if (textline
== NULL
){
384 crashAndBurn("Unexpected end of file in stringtable",
385 lineNumber
, lineFile
, "");
388 if (strchr(textline
, '\"') != NULL
){
389 // Cannot use strtok because it will ignore quotes in resources
390 // that appear as "this has a ""quoted"" string"
391 pchStartQuote
= strchr(textline
, '\"');
392 pchEndQuote
= strrchr(textline
, '\"');
394 if (pchEndQuote
!= NULL
&& pchEndQuote
!= pchStartQuote
)
396 stringLen
= pchEndQuote
- pchStartQuote
+ 1;
397 stringValue
= (LPSTR
)malloc(stringLen
+ 1);
398 if (stringValue
== NULL
)
399 crashAndBurn("Out of memory - stringValue",
400 oldLineNumber
, lineFile
, textline
);
401 stringValue
= strncpy(stringValue
, pchStartQuote
, stringLen
);
402 stringValue
[stringLen
-1] = '\0';
406 /// Found a line which is not blank, but does not have
407 /// a string surrounded by quotes in it
408 crashAndBurn("StringID with no StringValue in STRINGTABLE",
409 oldLineNumber
, lineFile
, "");
413 stringValueFormatted
= FormatString(stringValue
+ 1); // skip over leading quote
414 if (stringValueFormatted
== NULL
){
415 crashAndBurn("Unknown escape sequence in String Value",
416 lineNumber
,lineFile
, textline
);
419 stringValueOut
= convertToUTF8(stringValueFormatted
);
420 free(stringValueFormatted
);
423 stringtable
[stringTableCounter
].StringID
= stringIDint
;
424 stringtable
[stringTableCounter
].StringValue
= stringValueOut
;
425 stringTableCounter
++;
427 // If there is a '}' after the string and new line char, end section
429 char * pchNewLine
= strchr(pchEndQuote
+ 1, '\n');
430 char * pchBrace
= strchr(pchEndQuote
+ 1, '}');
432 if (pchNewLine
!= NULL
&& pchBrace
!= NULL
&& pchNewLine
> pchBrace
)
436 textline
= alloctextline
;
437 if(fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
438 crashAndBurn("end of file before END in stringtable",
439 lineNumber
, lineFile
, "");
449 else if (!strcmp(firstword
, "#pragma")){
452 pragma
= strtok(NULL
, " (");
454 if(!strcmp(pragma
, "code_page")){
457 cpString
= strtok(NULL
, ")");
458 codepage
= strtoul(cpString
, NULL
, 0);
460 if(codepage
== 0){ //couldn't conver to int
461 crashAndBurn("Bad Format in code_page pragma",
462 lineNumber
, lineFile
, textline
);
465 if (!IsValidCodePage(codepage
)){
467 printf("WARNING, codepage %i is invalid\n", codepage
);
469 crashAndBurn("Invalid Code Page Value",
470 lineNumber
, lineFile
, textline
);
473 printf("Codepage pragma found, updating codepage to %i\n", codepage
);
475 else if(!strcmp(pragma
, "once")){
478 else if(!strcmp(pragma
, "GCC")){
482 crashAndBurn("unknown pragma", lineNumber
, lineFile
, textline
);
486 else if(!strcmp(firstword
, "typedef")){
488 ////SKIP ALL LINES UNTIL FIRST {, THEN STOP WHEN FIND } THAT MATCHES
490 printf("WARNING...TYPEDEF in %s:\n %s\n", lineFile
, textline
);
493 textline
= alloctextline
;
494 fgets(textline
, BUF_SIZE
, strippedrc
);
497 while (strstr(textline
, "{") == NULL
){ //Skipping to first {
499 if (fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
500 crashAndBurn("Unexpected end of file", ++lineNumber
, lineFile
, "");
507 textline
= strstr(textline
, "{");
510 for (i
= 1; i
!= 0;){
511 //i is the number of { without }
514 if (strstr(textline
, "{") != NULL
){
515 textline
= strstr(textline
, "{");
519 else if (strstr(textline
, "}") != NULL
){
520 textline
= strstr(textline
, "}");
525 textline
= alloctextline
;
526 if(fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
527 crashAndBurn("Unexpected end of file", ++lineNumber
, lineFile
, "");
534 else { ///SOME OTHER RESOURCE
535 LPSTR secondword
= strtok(NULL
, " \t\n");
536 if (secondword
== NULL
)
539 if(!strcmp(firstword
, "FONT")
540 || !strcmp(firstword
, "AUTO3STATE")
541 || !strcmp(firstword
, "AUTORADIOBUTTON")
542 || !strcmp(firstword
, "COMBOBOX")
543 || !strcmp(firstword
, "CONTROL")
544 || !strcmp(firstword
, "CTEXT")
545 || !strcmp(firstword
, "DEFPUSHBUTTON")
546 || !strcmp(firstword
, "EDITTEXT")
547 || !strcmp(firstword
, "PUSHBOX")
548 || !strcmp(firstword
, "PUSHBUTTON")
549 || !strcmp(firstword
, "RADIOBUTTON")
550 || !strcmp(firstword
, "RTEXT")
551 || !strcmp(firstword
, "SCROLLBAR")
552 || !strcmp(firstword
, "STATE3")
553 || !strcmp(firstword
, "CAPTION")
554 || !strcmp(firstword
, "LANGUAGE")
555 || !strcmp(firstword
, "MENUITEM")
556 || !strcmp(firstword
, "STYLE")
558 if (verbose
) //These resources are one line of text in resource file
559 printf("Resource %s found on line % i in \n\t%s, ignoring\n",
560 firstword
, lineNumber
, lineFile
);
565 else if(!strcmp(secondword
, "TYPELIB")
566 || !strcmp(secondword
, "typelib")
567 || !strcmp(secondword
, "ICON")
568 || !strcmp(secondword
, "BITMAP")
569 || !strcmp(secondword
, "CURSOR")
570 || !strcmp(secondword
, "REGISTRY")
571 || !strcmp(secondword
, "FONT")
572 || !strcmp(secondword
, "MESSAGETABLE")){
573 if (verbose
) //These resources are one line of text in resource file
574 printf("Resource %s found on line % i in \n\t%s, ignoring\n",
575 secondword
, lineNumber
, lineFile
);
580 else if (!strcmp(secondword
, "VERSIONINFO")
581 || !strcmp(secondword
, "TOOLBAR")
582 || !strcmp(secondword
, "MENU")
583 || !strcmp(secondword
, "ACCELERATORS")
584 || !strcmp(secondword
, "DIALOG")
585 || !strcmp(secondword
, "TEXTINCLUDE")
586 || !strcmp(secondword
, "DIALOGEX")
587 || !strcmp(secondword
, "MENUEX")
588 || !strcmp(secondword
, "RCDATA")
589 || !strcmp(firstword
, "POPUP")){
591 // THESE RESOURCES TAKE UP MORE THEN ONE LINE, DELIMITED BY
592 // BEGIN/END TAGS OR BRACES { }
596 if (!strcmp(firstword
, "POPUP")){
597 secondword
= firstword
;
601 printf("Resource %s found on line % i in \n\t%s, ignoring\n",
602 secondword
, lineNumber
, lineFile
);
605 removeDefinition(strippedrc
, textline
, TRUE
, &lineNumber
, &lineFile
);
609 else { //USER DEFINED RESOURCE
611 // OF TWO FORMS, EITHER ONE LINE WITH FILENAME SPECIFYING RESOURCE
612 // OR MULTIPLE LINES, WITH RESOURCE IN SCRIPT SURROUNDED BY BEGIN/END
613 // TAGS OR BRACES { }
618 printf("UNKNOWN resource %s found on line % i in \n\t%s, ignoring\n",
619 secondword
, lineNumber
, lineFile
);
621 thirdword
= strtok(NULL
, " \t\n");
623 if (thirdword
!= NULL
){ // RESOURCE DEFINED IN OTHER FILE, ONE LINE
627 else { // RESOURCE IN RESOURCE SCRIPT, SKIP DEFINITION
629 textline
= alloctextline
;
630 fgets(textline
, BUF_SIZE
, strippedrc
);
633 removeDefinition(strippedrc
, textline
, FALSE
, &lineNumber
, &lineFile
);
638 textline
= alloctextline
;
643 qsort((void *)stringtable
, stringTableCounter
, //sort array by id
644 sizeof(STRING_TABLE_ENTRY
), steCompare
);
648 printf("Opening %s for writing\n",outFilename
);
650 outfile
= fopen(outFilename
,"w+b");
651 if (outfile
== NULL
){
652 crashAndBurn("Couldn't open file for output",UNKNOWN_LINE_NUMBER
, "", "");
656 for(i
=0; i
<stringTableCounter
; i
++){
658 if (stringtable
[i
].StringID
== lastValue
){ //CHECK FOR DOUBLES
661 errorMessage
= (LPSTR
)malloc(sizeof("Duplicate StringID for Values: ") +
662 strlen(stringtable
[i
-1].StringValue
) +
664 strlen(stringtable
[i
].StringValue
) - 1);
665 if (errorMessage
== NULL
){
666 crashAndBurn("Out of memory",
667 UNKNOWN_LINE_NUMBER
, "", "");
670 errorMessage
= strcpy(errorMessage
, "Duplicate StringID for Values: ");
671 errorMessage
= strcat(errorMessage
, stringtable
[i
-1].StringValue
);
672 errorMessage
= strcat(errorMessage
, ", ");
673 errorMessage
= strcat(errorMessage
, stringtable
[i
].StringValue
);
675 crashAndBurn(errorMessage
, UNKNOWN_LINE_NUMBER
, "", "");
677 //ERROR MESSAGE SHOWS VALUES WHICH SHARE AN ID
682 OutFileWritten
= TRUE
;
683 // Save string length
684 stringtable
[i
].StringLen
= strlen(stringtable
[i
].StringValue
);
687 filelenCur
+= fwrite(stringtable
[i
].StringValue
, 1, stringtable
[i
].StringLen
, outfile
);
689 lastValue
= stringtable
[i
].StringID
;
691 for(i
=0; i
<stringTableCounter
; i
++){
692 // Done with the StringValue, free it up
693 free(stringtable
[i
].StringValue
);
696 // If odd # of bytes written, pad with an extra to make the table entries
702 fwrite(&ch
, 1, sizeof(ch
), outfile
);
705 // Write out the table
707 for(i
=0; i
<stringTableCounter
; i
++){
708 uID
= VAL16(stringtable
[i
].StringID
);
709 stringoffset
= VAL32(filelenCur
);
710 filelenCur
+= stringtable
[i
].StringLen
;
712 fwrite(&uID
, 1, sizeof(uID
), outfile
);
714 fwrite(&stringoffset
, 1, sizeof(stringoffset
), outfile
);
717 stringoffset
= VAL32(filelenCur
);
719 fwrite(&uID
, 1, sizeof(uID
), outfile
);
721 fwrite(&stringoffset
, 1, sizeof(stringoffset
), outfile
);
724 printf("Output file is: %s\n\n", outFilename
);
727 // CLOSE BOTH OUTPUT FILE AND PREPROCESSOR (.i) FILE
729 if (strippedrc
!= NULL
){
732 if (outfile
!= NULL
){
735 if (!OutFileWritten
) {
737 printf("Removing output file - no STRINGTABLEs were found\n");
739 DeleteFileA(outFilename
);
744 if(DeleteFileA(strippedFilename
)){
746 printf("Removing %s\n", strippedFilename
);
750 if (lineFile
!= NULL
) {
761 ///////////////////////////////////////////////////////////////////////////////
763 // ConsoleControlHandler
766 // dwCtrlType: the type of signal to be handled
769 // false to indicate the program should exit
771 ///////////////////////////////////////////////////////////////////////////////
774 ConsoleControlHandler(DWORD dwCtrlType
)
776 if (strippedrc
!= NULL
){
779 if (outfile
!= NULL
){
782 DeleteFileA(strippedFilename
);
783 DeleteFileA(outFilename
);
788 ///////////////////////////////////////////////////////////////////////////////
792 ///////////////////////////////////////////////////////////////////////////////
794 void removeDefinition(FILE * file
,
796 BOOL linesBeforeBegin
,
800 // LPSTR textline = malloc(BUF_SIZE);
804 if(linesBeforeBegin
){
805 ////SKIP ALL LINES UNTIL FIRST BEGIN OR {
806 ////THEN STOP WHEN FIND END or }THAT MATCHES
808 while ((strstr(textline
, "BEGIN") == NULL
) &&
809 (strstr(textline
, "{") == NULL
)){
810 if (fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
811 crashAndBurn("Unexpected end of file",
812 ++(*lineNumber
), (*lineFile
), "");
819 else if ((strstr(textline
, "BEGIN") == NULL
) &&
820 (strstr(textline
, "{") == NULL
)){
821 crashAndBurn("Bad Format in User Defined Resource",
822 *lineNumber
, *lineFile
, textline
);
825 if(strstr(textline
, "{") != NULL
){ //Brace broke the loop
826 textline
= strstr(textline
, "{");
829 else{ //BEGIN broke the loop
830 if(fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
831 crashAndBurn("Unexpected end of file",
832 ++(*lineNumber
), (*lineFile
), "");
839 for (i
= 1; i
!= 0;){
843 textlinetotok
= (LPSTR
)malloc(strlen(textline
) + 1);
844 if (textlinetotok
== NULL
)
845 crashAndBurn("Out of memory -textlinetotok",
846 UNKNOWN_LINE_NUMBER
,"","");
847 textlinetotok
= strcpy(textlinetotok
, textline
);
849 word
= strtok(textlinetotok
, " \t\n");
853 if (textline
[0] == '\0')
855 //i is the number of opens not yet closed
856 if (!strcmp(word
, "BEGIN")){
858 if(fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
859 crashAndBurn("Unexpected end of file",
860 ++(*lineNumber
), (*lineFile
), "");
866 else if (strstr(textline
, "{") != NULL
){
868 textline
= strstr(textline
, "{");
871 else if (!strcmp(word
, "END")){
874 if(fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
875 crashAndBurn("Unexpected end of file",
876 ++(*lineNumber
), (*lineFile
), "");
883 else if (strstr(textline
, "}") != NULL
){
885 textline
= strstr(textline
, "}");
889 if(fgets(textline
, BUF_SIZE
, strippedrc
) == NULL
){
890 crashAndBurn("Unexpected end of file",
891 ++(*lineNumber
), (*lineFile
), "");
900 ///////////////////////////////////////////////////////////////////////////////
905 // message: Message to be displayed to stderr
906 // lineNumber: Line number in .rc file in which error occured, or
907 // UNKNOWN_LINE_NUMBER if not line number specific or line
909 // file: File in which the error occured, if using known line number
910 // badline: The line of text which caused the error, if using known line
913 ///////////////////////////////////////////////////////////////////////////////
915 void crashAndBurn(LPSTR message
, int lineNumber
, LPSTR file
, LPSTR badline
){
917 if (strippedrc
!= NULL
){
920 if (outfile
!= NULL
){
923 if (strippedFilename
)
925 DeleteFileA(strippedFilename
);
929 DeleteFileA(outFilename
);
932 fprintf(stderr
, "resourcecompiler: fatal error RC0001 : ");
934 if(lineNumber
!= UNKNOWN_LINE_NUMBER
){
935 fprintf(stderr
, "on line %d in %s: \n", lineNumber
, file
);
936 if (badline
!= NULL
&& badline
[0] != '\0') {
937 fprintf(stderr
, "resourcecompiler: %s\n", badline
);
940 fprintf(stderr
, "resourcecompiler: %s\n", message
);
945 ///////////////////////////////////////////////////////////////////////////////
950 // argc: Number of arguments to be processed
951 // argv[]: Array of parameters
952 // compilerOptions: Options to be passed to the compiler for preprocessing
954 ///////////////////////////////////////////////////////////////////////////////
956 void ProcessParameters(int argc
, LPSTR argv
[], LPSTR
* compilerOptions
)
962 if (!strcmp(argv
[0], "/?") ||
963 !strcmp(argv
[0], "-?") ||
964 !strcmp(argv
[0], "/h") ||
965 !strcmp(argv
[0], "-h")){
969 // Allow absolute paths
970 else if (**argv
== '-') {
971 #else // PLATFORM_UNIX
972 else if(**argv
== '/' || **argv
== '-'){
973 #endif // PLATFORM_UNIX
974 //LAST ARGUMENT SHOULD NOT BE OPTION, SHOULD BE FILENAME
975 printUsage("A filename must be specified\n");
978 else{ //One arguement is filename
983 inFilename
= (LPSTR
)malloc(strlen(argv
[0]) + 1);
984 if (inFilename
== NULL
){
985 crashAndBurn("Out of memory - inFilename",
986 UNKNOWN_LINE_NUMBER
, "", "");
989 strcpy(inFilename
, argv
[0]);
991 inFileAppend
= (LPSTR
)malloc(strlen(argv
[0]) + sizeof(".rc"));
992 if (inFileAppend
== NULL
){
993 crashAndBurn("Out of memory - inFileAppend",
994 UNKNOWN_LINE_NUMBER
, "", "");
997 inFileAppend
= strcpy(inFileAppend
, argv
[0]);
998 inFileAppend
= strcat(inFileAppend
, ".rc");
1000 inFile
= fopen(inFilename
, "r");
1001 inFile2
= fopen(inFileAppend
, "r");
1003 if(inFile
== NULL
&& inFile2
== NULL
){
1006 errorMessage
= (LPSTR
)malloc(sizeof("Cannot Open File: ") +
1007 + strlen(inFilename
));
1008 if (errorMessage
== NULL
)
1009 crashAndBurn("Out of memory - errorMessage",
1010 UNKNOWN_LINE_NUMBER
, "", "");
1012 errorMessage
= strcpy(errorMessage
, "Cannot Open File: ");
1013 errorMessage
= strcat(errorMessage
, inFilename
);
1017 crashAndBurn(errorMessage
, UNKNOWN_LINE_NUMBER
, "", "");
1022 if (inFile2
!= NULL
){
1024 if (inFile
== NULL
){
1026 inFilename
= inFileAppend
;
1033 if (inFile
!= NULL
){
1038 if (outFilename
== NULL
){
1039 outFilename
= changeExtension(inFilename
, ".rc", ".satellite");
1044 else if ( (**argv
== '/') || (**argv
== '-')){
1045 for(p
= *argv
+ 1; *p
!= '\0'; p
++){
1046 switch(tolower(*p
)){
1063 codepage
= strtoul(p
, NULL
, 16);
1064 if (!IsValidCodePage(codepage
)){
1066 printf("WARNING, codepage %i is invalid\n", codepage
);
1068 crashAndBurn("Invalid Code Page Value",
1069 UNKNOWN_LINE_NUMBER
, "", "");
1086 *compilerOptions
= (LPSTR
)realloc(*compilerOptions
,
1087 strlen(*compilerOptions
) +
1088 sizeof(DEFINE_PREFIX
) +
1091 if (*compilerOptions
== NULL
){
1092 crashAndBurn("Out of memory - compilerOptions",
1093 UNKNOWN_LINE_NUMBER
, "", "");
1095 *compilerOptions
= strcat(*compilerOptions
, DEFINE_PREFIX
);
1096 *compilerOptions
= strcat(*compilerOptions
, p
);
1097 *compilerOptions
= strcat(*compilerOptions
, " ");
1104 printUsage("'f' must be followed by 'o' for renaming output\n");
1109 if(!strcmp(outFilename
,""))
1118 p
+= strlen(outFilename
) - 1;
1120 printf("Set output file name to %s\n", outFilename
);
1133 *compilerOptions
= (LPSTR
)realloc(*compilerOptions
,
1134 strlen(*compilerOptions
) +
1135 sizeof(INCLUDE_PREFIX
) +
1138 if (*compilerOptions
== NULL
){
1139 crashAndBurn("Out of memory - compilerOptions",
1140 UNKNOWN_LINE_NUMBER
, "", "");
1142 *compilerOptions
= strcat(*compilerOptions
, INCLUDE_PREFIX
);
1143 *compilerOptions
= strcat(*compilerOptions
, p
);
1144 *compilerOptions
= strcat(*compilerOptions
, " ");
1159 //THIS ARGUMENT IS NOT USED BY RC!!
1160 //Codepage is set by #pragma(codepage) or \c
1177 *compilerOptions
= (LPSTR
)realloc(*compilerOptions
,
1178 strlen(*compilerOptions
) +
1182 if (*compilerOptions
== NULL
){
1183 crashAndBurn("Out of memory - compilerOptions",
1184 UNKNOWN_LINE_NUMBER
, "", "");
1186 *compilerOptions
= strcat(*compilerOptions
, "/U");
1187 *compilerOptions
= strcat(*compilerOptions
, p
);
1188 *compilerOptions
= strcat(*compilerOptions
, " ");
1194 printf("Processing Arguments...\n");
1200 *compilerOptions
= (LPSTR
)realloc(*compilerOptions
,
1201 strlen(*compilerOptions
) +
1203 if (*compilerOptions
== NULL
){
1204 crashAndBurn("Out of memory - compilerOptions",
1205 UNKNOWN_LINE_NUMBER
, "", "");
1207 *compilerOptions
= strcat(*compilerOptions
, "/X ");
1211 //ARGUMENT IGNORED, PROVIDED FOR COMPATIBILITY
1225 printUsage("Unknown argument\n");
1230 else{ //ARGUMENT THAT DOESN'T START WITH / OR - BUT IS NOT LAST
1231 printUsage("Unknown argument, no - or /\n");
1237 ///////////////////////////////////////////////////////////////////////////////
1241 // Prints the Usage Statement for rc
1244 // message: A message to be printed before the usage statemnt, often
1245 // indicating what caused the usage statement to be printed
1247 ///////////////////////////////////////////////////////////////////////////////
1249 void printUsage(LPSTR message
){
1252 printf("Usage: resourcecompiler [options] inputfile\n");
1253 printf("\nOptions: \n\n");
1254 printf("\t/? Displays a list of resource compiler command-line options.\n");
1255 printf("\t/d Defines a symbol for the preprocessor that you can test\n");
1256 printf("\t with the ifdef directive\n");
1257 printf("\t/fo Rename output file\n");
1258 printf("\t/h Displays a list of command-line options\n");
1259 printf("\t/i Searches the specified directory before searching the\n");
1260 printf("\t directories specified by the INCLUDE enviornment variable\n");
1261 printf("\t/c specifies the codepage to be used for compilation\n");
1262 printf("\t/n Null terminates all strings in the string table\n");
1263 printf("\t/r Ignored. Provided for compatibility with existing\n");
1264 printf("\t makefiles\n");
1265 printf("\t/l Ignored. Provided for compatibility with existing\n");
1266 printf("\t makefiles\n");
1268 printf("\t/z Ignored. Provided for compatibility with existing\n");
1269 printf("\t makefiles\n");
1271 printf("\t/u Undefines a symbol for the preprocessor\n");
1272 printf("\t/v Displays messages that report on the progress of the\n");
1273 printf("\t compiler\n");
1274 printf("\t/w Warns if invalid codepage (default is error)\n");
1275 printf("\t/x Prevents RC from checking INCLUDE enviornment variable\n");
1276 printf("\t when searching for header files or resource files\n\n");
1281 ///////////////////////////////////////////////////////////////////////////////
1285 // Calls the C preprocessor on the input file to produce the stripped file.
1288 // compilerOptions: Command Line arguments to be passed to the compiler
1290 ///////////////////////////////////////////////////////////////////////////////
1291 void preProcessFile(LPSTR compilerOptions
)
1294 PROCESS_INFORMATION procInfo
;
1295 STARTUPINFOA startInfo
;
1298 SECURITY_ATTRIBUTES secAttr
;
1300 commandLine
= (LPSTR
)malloc(strlen(COMPILER_NAME
) +
1301 strlen(compilerOptions
) +
1302 strlen(inFilename
) +
1303 strlen("\"\"") + 1);
1304 if (commandLine
== NULL
){
1305 crashAndBurn("Out of memory - commandLine", UNKNOWN_LINE_NUMBER
, "", "");
1308 commandLine
= strcpy(commandLine
, COMPILER_NAME
);
1310 strcat(commandLine
, compilerOptions
);
1311 strcat(commandLine
, "\"");
1312 strcat(commandLine
, inFilename
);
1313 strcat(commandLine
, "\"");
1315 memset(&startInfo
, 0, sizeof(startInfo
));
1316 startInfo
.cb
= sizeof(startInfo
);
1318 memset(&secAttr
, 0, sizeof(secAttr
));
1319 secAttr
.nLength
= sizeof(secAttr
);
1320 secAttr
.bInheritHandle
= TRUE
;
1322 if ((hPreFile
= CreateFileA(strippedFilename
, GENERIC_WRITE
, 0, &secAttr
,
1323 CREATE_ALWAYS
, 0, NULL
)) == INVALID_HANDLE_VALUE
) {
1324 crashAndBurn("Failed to create temporary file for preprocessor",
1325 UNKNOWN_LINE_NUMBER
,"","");
1328 startInfo
.dwFlags
= STARTF_USESTDHANDLES
;
1329 startInfo
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
1330 startInfo
.hStdOutput
= hPreFile
;
1331 startInfo
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
1334 printf("\n\n\nC compiler command line is: %s\n\n\n", commandLine
);
1337 if(!CreateProcessA(NULL
,
1347 crashAndBurn("Failed to spawn preprocessor", UNKNOWN_LINE_NUMBER
,"","");
1350 WaitForSingleObject( procInfo
.hProcess
, INFINITE
);
1352 GetExitCodeProcess(procInfo
.hProcess
, &exitCode
);
1355 crashAndBurn("Preprocessor Failed", UNKNOWN_LINE_NUMBER
, "", "");
1358 CloseHandle(procInfo
.hProcess
);
1359 CloseHandle(procInfo
.hThread
);
1360 CloseHandle(hPreFile
);
1365 ///////////////////////////////////////////////////////////////////////////////
1370 // inputString: pointer to string of characters to be converted
1373 // Pointer to a string converted into UTF8
1375 ///////////////////////////////////////////////////////////////////////////////
1377 LPSTR
convertToUTF8(LPSTR inputString
)
1387 numOfWideChars
= MultiByteToWideChar(codepage
, 0,
1389 strlen(inputString
),
1392 wideString
= (LPWSTR
)malloc(numOfWideChars
*sizeof(WCHAR
));
1393 if (wideString
== NULL
){
1394 crashAndBurn("Out of memory - wideString", UNKNOWN_LINE_NUMBER
, "", "");
1397 i
= MultiByteToWideChar(codepage
,0,inputString
,
1398 strlen(inputString
),wideString
,
1402 error
= GetLastError();
1403 if (error
== ERROR_INSUFFICIENT_BUFFER
)
1404 crashAndBurn("Converting to UTF8 - INSUFFICIENT_BUFFER\n",
1405 UNKNOWN_LINE_NUMBER
, "", "");
1406 else if (error
== ERROR_INVALID_FLAGS
)
1407 crashAndBurn("Converting to UTF8 - INVALID_FLAGS\n",
1408 UNKNOWN_LINE_NUMBER
, "", "");
1409 else if (error
== ERROR_INVALID_PARAMETER
)
1410 crashAndBurn("Converting to UTF8 - INVALID_PARAMETER 1\n",
1411 UNKNOWN_LINE_NUMBER
, "", "");
1412 else if (error
== ERROR_NO_UNICODE_TRANSLATION
)
1413 crashAndBurn("Converting to UTF8 - NO_UNICODE_TRANSLATION\n",
1414 UNKNOWN_LINE_NUMBER
, "", "");
1416 crashAndBurn("Error converting to UTF8\n",
1417 UNKNOWN_LINE_NUMBER
, "", "");
1421 numOfOutChars
= WideCharToMultiByte(CP_UTF8
, 0, wideString
,
1422 numOfWideChars
, NULL
, 0, NULL
, NULL
);
1425 outputString
= (LPSTR
)malloc(numOfOutChars
+ 1);
1426 if (outputString
== NULL
){
1427 crashAndBurn("Out of memory - outputString", UNKNOWN_LINE_NUMBER
, "", "");
1431 i
= WideCharToMultiByte(CP_UTF8
, 0, wideString
,
1432 numOfWideChars
, outputString
,
1433 numOfOutChars
, NULL
, NULL
);
1436 error
= GetLastError();
1437 if (error
== ERROR_INSUFFICIENT_BUFFER
)
1438 crashAndBurn("Converting to UTF8 - INSUFFICIENT_BUFFER\n",
1439 UNKNOWN_LINE_NUMBER
, "", "");
1440 else if (error
== ERROR_INVALID_FLAGS
)
1441 crashAndBurn("Converting to UTF8 - INVALID_FLAGS\n",
1442 UNKNOWN_LINE_NUMBER
, "", "");
1443 else if (error
== ERROR_INVALID_PARAMETER
)
1444 crashAndBurn("Converting to UTF8 - INVALID_PARAMETER 1\n",
1445 UNKNOWN_LINE_NUMBER
, "", "");
1447 crashAndBurn("Error converting to UTF8\n",
1448 UNKNOWN_LINE_NUMBER
, "", "");
1451 outputString
[numOfOutChars
] = '\0';
1454 return outputString
;
1457 ///////////////////////////////////////////////////////////////////////////////
1462 // inputString: pointer to string of characters to be formatted
1465 // all character sequences interpretable as escape characters are
1466 // replaced by the corresponding character
1468 ///////////////////////////////////////////////////////////////////////////////
1470 LPSTR
FormatString(LPSTR inputString
)
1472 LPSTR formattedString
;
1473 int i
,j
, stringLength
;
1477 // Gets longer only when % is present
1478 formattedString
= (LPSTR
)malloc(strlen(inputString
) + 1);
1480 if (formattedString
== NULL
){
1481 crashAndBurn("Out of memory - formattedString",
1482 UNKNOWN_LINE_NUMBER
, "", "");
1485 stringLength
= (int)strlen(inputString
);
1487 for (i
= 0, j
= 0; i
< stringLength
; i
++, j
++){
1489 if ((int) inputString
[i
] == '\\'){
1490 //replace with escape character
1491 numOfCharsUsed
= getEscapeCharacter(&inputString
[i
+1], &escchar
);
1492 if (numOfCharsUsed
== 0){
1493 free(formattedString
);
1496 i
+= numOfCharsUsed
;
1497 inputString
[i
] = escchar
;
1500 if (inputString
[i
] == '\"' && inputString
[i
+1] == '\"') {
1501 // replace "" with "
1502 formattedString
[j
] = inputString
[i
];
1506 //use character given
1507 formattedString
[j
] = inputString
[i
];
1510 formattedString
[j
] = '\0';
1512 return formattedString
;
1515 ///////////////////////////////////////////////////////////////////////////////
1519 // Changes the extension from old to new, or appends new filename didn't
1520 // have extension old
1523 // filename: filename on which to change extension
1524 // oldExt: old extension
1525 // newExt: new extension
1528 // Pointer to a string containing the new filename
1530 ///////////////////////////////////////////////////////////////////////////////
1531 LPSTR
changeExtension(LPSTR filename
, LPSTR oldExt
, LPSTR newExt
)
1537 returnValue
= (LPSTR
)malloc(strlen(filename
) + strlen(newExt
));
1538 if (returnValue
== NULL
)
1539 crashAndBurn("Out of memory - returnValue", UNKNOWN_LINE_NUMBER
, "", "");
1541 returnValue
= strcpy(returnValue
, filename
);
1543 tempString
= strstr(returnValue
, oldExt
);
1544 if (tempString
!= NULL
)
1545 tempString
[0] = '\0';
1546 returnValue
= strcat(returnValue
, newExt
);
1548 return(returnValue
);
1553 ///////////////////////////////////////////////////////////////////////////////
1556 // (for use with qsort)
1559 // first: pointer to first STRING_TABLE_ENTRY to be compared
1560 // second: pointer to second STRING_TABLE_ENTRY to be compared
1563 // negative value if first->StringID < second->StringID
1564 // zero if first.StringID = second.StringID
1565 // positive value if first->StringID > second->StringID
1567 ///////////////////////////////////////////////////////////////////////////////
1569 int __cdecl
steCompare(const void *first
, const void *second
){
1573 if (((STRING_TABLE_ENTRY
* )first
)->StringID
>
1574 ((STRING_TABLE_ENTRY
* )second
)->StringID
)
1576 else if (((STRING_TABLE_ENTRY
* )first
)->StringID
==
1577 ((STRING_TABLE_ENTRY
* )second
)->StringID
)
1585 ///////////////////////////////////////////////////////////////////////////////
1590 // line: line of the format #line linenumber filename. To be used to
1591 // determine new values for lineNumber and lineFile.
1592 // lineNumber: pointer to the int which holds current line number
1593 // lineFile: pointer to the LPSTR which holds the current file
1594 // corresponding to lineNumber
1596 ///////////////////////////////////////////////////////////////////////////////
1598 void updateLineNumber(LPSTR line
, int * lineNumber
, LPSTR
* lineFile
){
1600 LPSTR lineNumberString
;
1603 LPSTR fileTokenCopy
;
1605 linetotok
= (LPSTR
)malloc(strlen(line
) + 1);
1606 if (linetotok
== NULL
)
1607 crashAndBurn("Out of memory - linetotok", UNKNOWN_LINE_NUMBER
, "", "");
1608 strcpy(linetotok
, line
);
1610 strtok(linetotok
, " "); ///removes #line
1612 lineNumberString
= strtok(NULL
, "\"");
1613 *lineNumber
= strtoul(lineNumberString
, NULL
, 0) - 1;
1615 fileToken
= strtok(NULL
, "\"");
1616 fileTokenCopy
= (LPSTR
)malloc (strlen(fileToken
) + 1);
1617 if (fileTokenCopy
== NULL
)
1618 crashAndBurn("Out of memory - fileTokenCopy", UNKNOWN_LINE_NUMBER
, "", "");
1619 strcpy(fileTokenCopy
, fileToken
);
1621 if (*lineFile
!= NULL
) {
1624 *lineFile
= FormatString(fileTokenCopy
);
1625 free(fileTokenCopy
);
1627 if (*lineFile
== NULL
){
1629 crashAndBurn("Error in format of preprocessed file",
1630 UNKNOWN_LINE_NUMBER
, "", "");
1633 if (*lineFile
== NULL
){
1634 crashAndBurn("Out of memory - lineFile", UNKNOWN_LINE_NUMBER
, "", "");
1639 ///////////////////////////////////////////////////////////////////////////////
1641 // clearBlanksAndLineUpdates
1644 // file: pointer to file from which the lines are to be taken
1645 // lineNumber: pointer to the int which holds current line number
1646 // lineFile: pointer to the LPSTR which holds the current file
1647 // corresponding to lineNumber
1648 // textline: buffer for lines read from file. if checkCurrent is true,
1649 // will be read as first line to be examined, at return,
1650 // will hold the value of the first non blank or
1651 // line updating line.
1652 // checkCurrent: if true, the value of textline when the function is called
1653 // will be checked for blankness or line update. otherwise the
1654 // initial string in textline will be ignored
1656 ///////////////////////////////////////////////////////////////////////////////
1657 void clearBlanksAndLineUpdates(FILE * file
,
1663 //LOOP TO REMOVE EFFECTIVELY BLANK LINES, AND #line LINES
1666 //IF checkCurrent WAS SET TO TRUE, DON'T READ LINE FIRST TIME
1669 if(fgets(*textline
, BUF_SIZE
, file
) == NULL
){
1678 checkCurrent
= FALSE
;
1681 // Only recognize the prefix at the start of the line
1682 if(startsWithLineMarker(*textline
))
1683 updateLineNumber(*textline
, lineNumber
, lineFile
);
1685 }while((strspn(*textline
, " \t\n") == strlen(*textline
))
1686 || startsWithLineMarker(*textline
));
1690 ///////////////////////////////////////////////////////////////////////////////
1692 // startsWithLineMarker
1695 // line: a line in a preprocessed file
1698 // Whether the line starts with a preprocessor line directive
1700 ///////////////////////////////////////////////////////////////////////////////
1703 BOOL
startsWithLineMarker(const char *line
)
1706 return (line
[0] == LINEMARKER_PREFIX
&& (line
[1] == ' ' || isdigit(line
[1])));
1708 return (strstr(line
, (const char*)LINEMARKER_PREFIX
) == line
);
1712 ///////////////////////////////////////////////////////////////////////////////
1714 // getEscapeCharacter
1717 // input: pointer to string of characters to be interpreted as escape
1719 // output: pointer to location in which to store escape character
1722 // Number of characters used to form escape sequence if successfull,
1723 // 0 if string could not be interpreted
1725 ///////////////////////////////////////////////////////////////////////////////
1728 int getEscapeCharacter (char * input
, char * output
){
1736 for (i
= 0, value
= 0; isxdigit(input
[i
]); i
++){
1741 else if (islower(c
)){
1747 value
= (16 * value
) + c
;
1750 fprintf(stderr
, "Bad Hex value while converting escape character\n");
1753 else if (value
< 255){
1755 "Out of range Hex value while converting escape character\n");
1759 *output
= (char) value
;
1769 for ( i
= 0, value
= 0;
1770 input
[i
] <= '7' && input
[i
] >= '0' && i
<= 3;
1772 value
= (8 * value
) + (input
[i
] - '0');
1775 printf("Bad Octal value while converting escape character\n");
1778 else if (value
> 255){
1779 printf("Out of range Octal value while converting escape character\n");
1783 *output
= (char) value
;